﻿// echo partial file
#if FRONTEND
using Config;
using GameData.Domains.Character;
using GameData.Domains.Character.Creation;
using GameData.Domains.Map;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using TMPro;
using UnityEngine;
using System.Reflection;
using static NpcScan.Const;
using static Utils.Logger;
namespace NpcScan.Controller
{
    public class NpcScanController : MonoBehaviour
    {
        public View view;
        public KeyCode mainFormKey = KeyCode.F3;
        private bool isShow = false;
        private List<CharacterData> characterDataList=new List<CharacterData>();

        public void Awake()
        {
            if (view == null)
            {
                view = new View();
                view.Init();
                AddListener();
                HideUI();
                page = 1;
            }
        }

        public void AddListener()
        {
            view.ButtonNext.onClick.AddListener(() => NextPage());
            view.ButtonPrevious.onClick.AddListener(() => PreviousPage());
            view.ButtonSearch.onClick.AddListener(() => { SetOptions(); });
            view.ButtonUpdate.onClick.AddListener(() => GetAllCharacters());
            for (int index=(int)Model.CharacterInfo.姓名; index<(int)Model.CharacterInfo._END_; ++index)
            {
                int i = index;
                view.ButtonDic[(Model.CharacterInfo)i].onClick.AddListener(()=>SortClick(i));
            }
            for(int index=0;index<ROW_MAX;index++){
                int i = index;
                view.ResultLines[i].GetComponent<CButton>().onClick.AddListener(()=>OpenCharacterMenu(i));
            }
        }

        #region sort
        int sortClick_curridx=-1;
        bool is_reversed=false;
        public void SortClick(int index){
            if(sortClick_curridx==index){
                Model.Instance.CurrentDataList.Reverse();
                is_reversed=!is_reversed;
            } else {
                SortClickImpl(index);
                sortClick_curridx=index;
                is_reversed=false;
            }
            SearchResult(0);
        }
        public void RestoreSort(){
            if(sortClick_curridx!=-1){
                SortClickImpl(sortClick_curridx);
            }
            if(is_reversed){
                Model.Instance.CurrentDataList.Reverse();
            }
        }
        public void SortClickImpl(int index){
            if (index >= (int)Model.CharacterInfo.膂力 && index <= (int)Model.CharacterInfo.悟性){
                Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.maxMainAttributes[index - (int)Model.CharacterInfo.膂力]).ToList();
            }else if (index >= (int)Model.CharacterInfo.内功 && index<=(int)Model.CharacterInfo.乐器){
                Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.combatSkillQualifications[index - (int)Model.CharacterInfo.内功]).ToList();
            }else if (index >= (int)Model.CharacterInfo.音律 && index<=(int)Model.CharacterInfo.杂学){
                Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.lifeSkillQualifications[index - (int)Model.CharacterInfo.音律]).ToList();
            }else switch ((Model.CharacterInfo)index) {
                case Model.CharacterInfo.姓名:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => NMdict[character.name]).ToList();
                    break;
                case Model.CharacterInfo.年龄:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.curr).ToList();
                    break;
                case Model.CharacterInfo.性别:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.gender).ToList();
                    break;
                case Model.CharacterInfo.位置:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.location[0]).ThenBy(character => character.location[1]).ToList();
                    break;
                case Model.CharacterInfo.魅力:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.attraction).ToList();
                    break;
                case Model.CharacterInfo.归属:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.organizationInfo[0]).ToList();
                    break;
                case Model.CharacterInfo.身份:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.organizationInfo[1]).ToList();
                    break;
                case Model.CharacterInfo.立场:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.behaviorType).ToList();
                    break;
                case Model.CharacterInfo.婚姻:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.marriage).ToList();
                    break;
                case Model.CharacterInfo.内力:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.extra_neili).ToList();
                    break;
                case Model.CharacterInfo.战力:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.power).ToList();
                    break;
                case Model.CharacterInfo.心情:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => (sbyte)character.mood).ToList();
                    break;
                case Model.CharacterInfo.精纯:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.jingchun).ToList();
                    break;
                case Model.CharacterInfo.技艺成长:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.lifeSkillGrowthType).ToList();
                    break;
                case Model.CharacterInfo.功法成长:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.combatSkillGrowthType).ToList();
                    break;
                case Model.CharacterInfo.健康:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.maxLeftHealth).ToList();
                    break;
                case Model.CharacterInfo.好感:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.FavorabilityToTaiwu>-30001?character.FavorabilityToTaiwu:0).ToList();
                    break;
                case Model.CharacterInfo.入邪:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.xiangshuInfection).ToList();
                    break;
                case Model.CharacterInfo.奇书:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.LegendaryBookOwnerState).ToList();
                    break;
                case Model.CharacterInfo.心仪:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => (uint)character.ideal).ToList();
                    break;
                case Model.CharacterInfo.派系:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => (uint)character.faction).ToList();
                    break;
                case Model.CharacterInfo.领队:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => (uint)character.leader).ToList();
                    break;
                case Model.CharacterInfo.被拘:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => (uint)character.kidnapper).ToList();
                    break;
                case Model.CharacterInfo.周天运转:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.zhoutian_yunzhuan).ToList();
                    break;
                case Model.CharacterInfo.状态:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderBy(character => character.state).ToList();
                    break;
                case Model.CharacterInfo.前世:
                    Model.Instance.CurrentDataList = Model.Instance.CurrentDataList.OrderByDescending(character => character.samsara.Length).ToList();
                    break;
                case Model.CharacterInfo.物品:
                    Model.Instance.CurrentDataList.Sort(ItemCompare);
                    break;
            }
        }

        public int ItemCompare(CharacterData character1, CharacterData character2)
        {
            var Item1 = character1.items;
            var Item2 = character2.items;
            int length = Math.Min(Item1.Length, Item2.Length);
            for (int index = 0; index < length; ++index)
            {
                if (Item1[index]>>item_grade_shift < Item2[index]>>item_grade_shift)
                    return 1;
                else if (Item1[index]>>item_grade_shift > Item2[index]>>item_grade_shift)
                    return -1;
            }
            for (int index = 0; index < length; ++index)
            {
                if (Item1[index] < Item2[index])
                    return 1;
                else if (Item1[index] > Item2[index])
                    return -1;
            }
            return 0;
        }
        #endregion

        public static readonly MethodInfo OnClickStudent=typeof(UI_BuildingTaiwuShrine).GetMethod("OnClickStudent",(BindingFlags)(-1));
        public static readonly FieldInfo _studentGroupCharDataListBySearch=typeof(UI_BuildingTaiwuShrine).GetField("_studentGroupCharDataListBySearch",(BindingFlags)(-1));
        // public static readonly FieldInfo _skillQualificationMonitorListBySearch=typeof(UI_BuildingTaiwuShrine).GetField("_skillQualificationMonitorListBySearch",(BindingFlags)(-1));
        public void OpenCharacterMenu(int index)
        {
            UIManager.Instance.HideUI(UIElement.CharacterMenu);
            int dataIndex = (page - 1) * ROW_MAX + index;
            if (Model.Instance.CurrentDataList.Count > dataIndex)
            {
                CharacterData data = Model.Instance.CurrentDataList[dataIndex];
                if (data.isAlive == 1) {
                    if (View.ToggleDic[Model.Toggle.村民灌顶].isOn && UIElement.TaiwuShrine.Exist && data.organizationInfo[0]==16){
                        var shrine=(UI_BuildingTaiwuShrine)UIElement.TaiwuShrine.UiBase;
                        int i=0;
                        foreach(var character in (List<GameData.Domains.Character.Display.GroupCharDisplayData>)_studentGroupCharDataListBySearch.GetValue(shrine)){
                            if(character.CharacterId == data.id){
                                // MainEntry.logger($"{character.CharacterId} matches, i={i}");
                                view.root.GetComponent<Canvas>().sortingOrder = 600;
                                CommandKitBase.SetDisable(false);
                                if (view.blockClickGroup != null)
                                    view.blockClickGroup.interactable = true;
                                OnClickStudent.Invoke(shrine,new object[]{i});
                                return;
                            }
                            // MainEntry.logger($"{character.CharacterId} != {data.id}, data.organizationInfo[0]={data.organizationInfo[0]}");
                            i++;
                        }
                    }
                    view.root.GetComponent<Canvas>().sortingOrder = 400;
                    CommandKitBase.SetDisable(false);
                    if (view.blockClickGroup != null)
                        view.blockClickGroup.interactable = true;
                    GMFunc.EnterCharacterMenu(data.id);
                }
            }
        }
        public void Update()
        {
            if (Input.GetKeyUp(mainFormKey))
            {
                if (isShow)
                {
                    HideUI();
                    isShow = false;
                    CommandKitBase.SetDisable(false);
                }
                else if(!UIElement.Combat.Exist) {
                    ShowUI();
                    isShow = true;
                    CommandKitBase.SetDisable(true);
                    GetAllCharacters();
                    view.root.GetComponent<Canvas>().sortingOrder = 1001;
                }
            } else if(isShow){
                if(Model.updateidx!=-1){
                    Model.Instance.Update();
                } else if (_set_option){
                    _SetOptions();
                } else if (_search_index<ROW_MAX) {
                    if(View.ToggleDic[Model.Toggle.同时刷新].isOn){
                        while(_search_index<ROW_MAX){
                            update_search_result();
                        }
                    } else {
                        update_search_result();
                    }
                } else if (Input.GetKey(KeyCode.LeftAlt)) {
                    if (Input.GetKeyUp(KeyCode.PageUp))
                        view.ScrollView.transform.localScale += new Vector3(0.05f, 0.05f, 0);
                    else if (Input.GetKeyUp(KeyCode.PageDown))
                        view.ScrollView.transform.localScale -= new Vector3(0.05f, 0.05f, 0);
                } else if (Input.GetKey(KeyCode.LeftShift)) {
                    if (Input.GetKeyUp(KeyCode.PageUp))
                        view.InputContainer.transform.localScale += new Vector3(0.05f, 0.05f, 0);
                    else if (Input.GetKeyUp(KeyCode.PageDown))
                        view.InputContainer.transform.localScale -= new Vector3(0.05f, 0.05f, 0);
                } else if (Input.GetKeyUp(KeyCode.PageUp)) {
                    PreviousPage();
                } else if (Input.GetKeyUp(KeyCode.PageDown)) {
                    NextPage();
                } else if (Input.GetKeyUp(KeyCode.Return)) {
                    if (Model.Instance.AllDataList.Count == 0) {
                        GetAllCharacters();
                    } else {
                        SetOptions();
                    }
                }
            }
        }

        private unsafe void GetAllCharacters()
        {
            try{
                SingletonObject.getInstance<AsynchMethodDispatcher>().AsynchMethodCall(65535,65535,NpcScan.MainEntry.modInfo.ModId,"GetCharactersData", (int offset, GameData.Utilities.RawDataPool dataPool)=>{
                    GameData.Serializer.Serializer.Deserialize(dataPool, offset, ref NMdict);
                #if SPEEDTEST
                System.Diagnostics.Stopwatch w=System.Diagnostics.Stopwatch.StartNew();
                #endif

                    #if Json
                    string AllCharacterString;

                    using (var memoryMappedFile = MemoryMappedFile.OpenExisting("NpcScanData"))
                    {
                        using (var accessor = memoryMappedFile.CreateViewAccessor())
                        {
                #if SPEEDTEST
                w.Stop();
                UnityEngine.Debug.LogError($"<color=#FFFF00>fe open cost {w.ElapsedMilliseconds}</color>");
                w.Restart();
                #endif
                            byte[] data = new byte[accessor.Capacity];
                            accessor.ReadArray(0, data, 0, data.Length);
                #if SPEEDTEST
                w.Stop();
                UnityEngine.Debug.LogError($"<color=#FFFF00>fe read cost {w.ElapsedMilliseconds}</color>");
                w.Restart();
                #endif
                            AllCharacterString = new UTF8Encoding().GetString(data);
                #if SPEEDTEST
                w.Stop();
                UnityEngine.Debug.LogError($"<color=#FFFF00>fe encode cost {w.ElapsedMilliseconds}</color>");
                w.Restart();
                #endif
                        }
                    }
                    //string AllCharacterString = File.ReadAllText("NpcScanData.json");
                    characterDataList.Clear();
                    characterDataList=JsonConvert.DeserializeAnonymousType(AllCharacterString,characterDataList);
                    #else


                    using (var memoryMappedFile = MemoryMappedFile.OpenExisting("NpcScanData"))
                    {
                        using (var accessor = memoryMappedFile.CreateViewAccessor())
                        {
                            byte[] data = new byte[accessor.Capacity];
                            accessor.ReadArray(0, data, 0, data.Length);
                            characterDataList.Clear();
                            fixed(byte*ptr=data){
                                var count=*(int*)ptr;
                                var ptr2=ptr+4;
                                for(int i=0;i<count;i++){
                                    var res=new CharacterData();
                                    ptr2=res.Des(ptr2);
                                    characterDataList.Add(res);
                                }
                            }
                        }
                    }


                    #endif
                #if SPEEDTEST
                w.Stop();
                UnityEngine.Debug.LogError($"<color=#FFFF00>fe convert cost {w.ElapsedMilliseconds}</color>");
                w.Restart();
                #endif
                    // MainEntry.logger("前端收到"+characterDataList.Count+"个数据");
                    Model.Instance.SetData(characterDataList);

                #if SPEEDTEST
                w.Stop();
                UnityEngine.Debug.LogError($"<color=#FFFF00>fe fill cost {w.ElapsedMilliseconds}</color>");
                #endif
                    // MainEntry.logger("共筛选出"+Model.Instance.CurrentDataList.Count+"个数据");
                    SetOptions();
                });
            }catch (Exception e){
                logex(e);
                UnityEngine.Debug.LogError("<color=#FFFF00>找不到AsynchMethodDispatcher，天知道发生了什么……</color>");
                UnityEngine.Debug.LogError("<color=#FF00FF>你该不会直接在游戏主界面直接打开了NpcScan吧……</color>");
                UnityEngine.Debug.LogError("<color=#00FFFF>如果你没有把握，请不要把这几行报错信息放到任何地方……</color>");
                UnityEngine.Debug.LogError("<color=#0000FF>因为，这很大概率是你自己的问题。</color>");
                return;
            }
        }

        private int _page;
        public int page
        {
            get
            {
                return _page;
            }
            set
            {
                if (value == 0)
                {
                    _page = (Model.Instance.CurrentDataList.Count - 1) / ROW_MAX + 1;
                }
                else if (value > (Model.Instance.CurrentDataList.Count - 1) / ROW_MAX + 1)
                {
                    _page = 1;
                }
                else
                    _page = value;
            }
        }

        static string dead=null;
        static string none=null;

        static string purple=null;
        static string white=null;
        static string red=null;
        static int _search_index=ROW_MAX;
        static string[] state_str=new string[8];
        // static WorldMapModel instance; -> Utils.map

        static int startIndex = 0;
        static int length = 0;
        public void SearchResult(int direction)
        {
            dead=$"<color={Colors.Instance.GradeColors[0].ColorToHexString()}>已故</color>";
            none=$"<color={Colors.Instance.GradeColors[0].ColorToHexString()}>无</color>";
            red=Colors.Instance.GradeColors[8].ColorToHexString();
            purple=Colors.Instance.GradeColors[5].ColorToHexString();
            white=Colors.Instance.GradeColors[1].ColorToHexString();
            state_str[0]=$"<color={white}>有工作</color>";
            state_str[1]=$"<color={purple}>关押者</color>";
            state_str[2]=$"<color={red}>奇遇中</color>";
            state_str[3]=$"<color={red}>面壁呢</color>";
            state_str[4]=$"<color={red}>摊上大事了</color>";
            state_str[5]=$"<color={purple}>自由活动受限</color>";
            state_str[6]=$"<color={red}>请联系螺舟说有BUG</color>";
            state_str[7]=$"<color={white}>（有情况）</color>";
            if (direction > 0)
                page += 1;
            if (direction < 0)
                page -= 1;
            if (direction == 0)
            {
                page = 1;
            }

            view.PageCount.text = page + "/" + ((Model.Instance.CurrentDataList.Count-1) / ROW_MAX + 1);
            startIndex = (page - 1) * ROW_MAX;
            length = Math.Min(ROW_MAX, Model.Instance.CurrentDataList.Count - startIndex);
            Utils.map = SingletonObject.getInstance<WorldMapModel>();

            _search_index=0; // call refresh
        }
        static string[] bookType=new string[]{"无书","持书","持书\n入邪","持书\n入魔","无书\n亡魂","未知"};
        public void update_search_result(){
            int index=_search_index;
            _search_index++;
            List<TextMeshProUGUI> rowLabels = view.ResultTMP[index];
            if(index<length){
                CharacterData characterData = Model.Instance.CurrentDataList[startIndex + index];


                rowLabels[(int)Model.CharacterInfo.姓名].text = $"id: <color={Colors.Instance.GradeColors[characterData.organizationInfo[1]].ColorToHexString()}>{characterData.id}</color>\n{NMdict[characterData.name]}";//characterData.name;
                rowLabels[(int)Model.CharacterInfo.年龄].text = characterData.isAlive==1? $"{characterData.curr}({characterData.age})":$"享年{characterData.age}";
                rowLabels[(int)Model.CharacterInfo.性别].text = CommonUtils.GetGenderString((sbyte)characterData.gender);

                Location location = new Location(characterData.location[0], characterData.location[1]);
                if (location.AreaId == -1 || location.BlockId == -1)
                {
                    rowLabels[(int)Model.CharacterInfo.位置].text = $"无法到达地区";
                }
                else
                {
                    string state = MapState.Instance[Utils.map.Areas[location.AreaId].GetConfig().StateID].Name;
                    string area = Utils.map.Areas[location.AreaId].GetConfig().Name;
                    try
                    {
                        MapBlockData blockData = Utils.map.GetBlockData(location);
                        if (blockData != null)
                        {
                            int nameIndex = Utils.map.GetBlockNameIndex(blockData, Utils.map.GetAreaSize(blockData.AreaId));
                            string block = Utils.map.GetBlockName(location.AreaId, blockData.BlockId, blockData.TemplateId, nameIndex);
                            ByteCoordinate blockPos = blockData.GetBlockPos();
                            rowLabels[(int)Model.CharacterInfo.位置].text = $"{state} {area} {block} ({blockPos.X},{blockPos.Y})";
                        }
                        else
                        {
                            rowLabels[(int)Model.CharacterInfo.位置].text = $"{state} {area}";
                        }
                    }
                    catch
                    {
                        rowLabels[(int)Model.CharacterInfo.位置].text = $"非法位置";
                    }
                }

                string charm = CommonUtils.GetCharmLevelText((short)characterData.attraction, (sbyte)characterData.gender, 16, 1, CreatingType.IsFixedPresetType((byte)characterData.creatingType));
                rowLabels[(int)Model.CharacterInfo.魅力].text = View.Attraction?$"{charm}({characterData.attraction})":charm;

                OrganizationInfo organizationInfo = new OrganizationInfo((sbyte)characterData.organizationInfo[0], (sbyte)characterData.organizationInfo[1], Convert.ToBoolean(characterData.organizationInfo[2]), (short)characterData.organizationInfo[3]);
                short randomNameId = (short)(Utils.map.SettlementRandNameDict.ContainsKey(organizationInfo.SettlementId) ? Utils.map.SettlementRandNameDict[organizationInfo.SettlementId] : -1);
                rowLabels[(int)Model.CharacterInfo.归属].text = string.Format("{0}\n{1}",((byte)characterData.organizationInfo[0]).ToString("X2"),characterData.organization);

                rowLabels[(int)Model.CharacterInfo.身份].text = characterData.identify;

                rowLabels[(int)Model.CharacterInfo.立场].text = CommonUtils.GetBehaviorString((sbyte)characterData.behaviorType);
                rowLabels[(int)Model.CharacterInfo.婚姻].text = Utils.GetMariageStatu(characterData.marriage);
                rowLabels[(int)Model.CharacterInfo.心情].text = $"{CommonUtils.GetHappinessString(GameData.Domains.Character.HappinessType.GetHappinessType((sbyte)characterData.mood))}\n({(sbyte)characterData.mood})";
                rowLabels[(int)Model.CharacterInfo.内力].text = characterData.isAlive==1?$"<color={purple}>+{characterData.extra_neili}</color>":dead;
                rowLabels[(int)Model.CharacterInfo.战力].text = characterData.isAlive==1?$"<color={purple}>+{characterData.power}</color>":dead;
                rowLabels[(int)Model.CharacterInfo.精纯].text = characterData.jingchun.ToString();
                rowLabels[(int)Model.CharacterInfo.技艺成长].text = characterData.isAlive==1?Utils.GetQualificationGrowth(characterData.age, characterData.lifeSkillGrowthType):dead;
                rowLabels[(int)Model.CharacterInfo.功法成长].text = characterData.isAlive==1?Utils.GetQualificationGrowth(characterData.age, characterData.combatSkillGrowthType):dead;
                rowLabels[(int)Model.CharacterInfo.健康].text = characterData.isAlive==1?$"{characterData.health}/{characterData.maxLeftHealth}":dead;
                rowLabels[(int)Model.CharacterInfo.好感].text = CommonUtils.GetFavorString(characterData.FavorabilityToTaiwu);
                rowLabels[(int)Model.CharacterInfo.入邪].text = characterData.isAlive==1?characterData.xiangshuInfection.ToString():dead;
                rowLabels[(int)Model.CharacterInfo.奇书].text=bookType[Math.Min((uint)(characterData.LegendaryBookOwnerState+1),5)];

                var org=Organization.Instance[characterData.ideal];
                var orgnum=((byte)characterData.ideal).ToString("X2");
                rowLabels[(int)Model.CharacterInfo.心仪].text = org!=null ? (
                    $"<color={Colors.Instance.GradeColors[characterData.organizationInfo[1]].ColorToHexString()}>{orgnum}\n{org.Name}</color>"
                ) : (
                    (byte)characterData.ideal == 255?(characterData.isAlive==1?"未定":dead):((byte)characterData.ideal).ToString("X2")
                );

                rowLabels[(int)Model.CharacterInfo.派系].text = characterData.isAlive==1?(characterData.faction == -1?none:$"<color={(characterData.faction==characterData.id?purple:white)}>{characterData.faction}\n{NMdict[characterData.faction]}</color>"):dead;
                rowLabels[(int)Model.CharacterInfo.领队].text = characterData.isAlive==1?(characterData.leader == -1?none:$"<color={(characterData.leader==characterData.id?purple:white)}>{characterData.leader}\n{NMdict[characterData.leader]}</color>"):dead;
                rowLabels[(int)Model.CharacterInfo.被拘].text = characterData.isAlive==1?(characterData.kidnapper == -1?none:$"<color={red}>{characterData.kidnapper}\n{NMdict[characterData.kidnapper]}</color>"):dead;
                for (int attributeIndex = 0; attributeIndex < 6; ++attributeIndex){
                    rowLabels[(int)Model.CharacterInfo.膂力 + attributeIndex].text = characterData.maxMainAttributes[attributeIndex].ToString();
                }
                {
                    var neigong=Config.CombatSkill.Instance[characterData.zhoutian_yunzhuan];
                    rowLabels[(int)Model.CharacterInfo.周天运转].text = neigong==null?$"<color={Colors.Instance.GradeColors[0].ColorToHexString()}>无</color>":$"<color={Colors.Instance.GradeColors[neigong.Grade].ColorToHexString()}>{neigong.Name}</color>";
                }
                for (int combatSkillIndex = 0; combatSkillIndex < 14; ++combatSkillIndex)
                {
                    var text = rowLabels[(int)Model.CharacterInfo.内功 + combatSkillIndex].GetComponent<TextMeshProUGUI>();
                    text.text = characterData.combatSkillQualifications[combatSkillIndex].ToString();
                    text.color = CommonUtils.GetCharacterSkillColorByValue((short)characterData.combatSkillQualifications[combatSkillIndex]);
                }
                {
                    rowLabels[(int)Model.CharacterInfo.状态].text = characterData.isAlive==1?(characterData.state == 0?none:string.Join("\n",from i in new int[]{0,1,2,3,4,5,6,7} where (characterData.state & (1<<i))>0 select state_str[i])):dead;
                }
                for (int lifeSkillIndex = 0; lifeSkillIndex < 16; ++lifeSkillIndex)
                {
                    var text = rowLabels[(int)Model.CharacterInfo.音律 + lifeSkillIndex].GetComponent<TextMeshProUGUI>();
                    text.text = characterData.lifeSkillQualifications[lifeSkillIndex].ToString();
                    text.color = CommonUtils.GetCharacterSkillColorByValue((short)characterData.lifeSkillQualifications[lifeSkillIndex]);
                }

                rowLabels[(int)Model.CharacterInfo.前世].text = string.Join(",", characterData.preexistenceCharacterNames).Replace("\n","");

                // rowLabels[(int)Model.CharacterInfo.物品].renderMode =  TMPro.TextRenderFlags.Render;
                var strlst=new string[9];
                int count=0;
                const string holder="><";
                for(int i=0;i<9;i++){
                    int g=8-i;
                    var list=(from item in characterData.items where (item>>item_grade_shift) == g select Utils.GetItemName(item&(item_id_mask|(item_type_mask<<item_type_shift)))).ToList();
                    strlst[i] = count<100?string.Format("<color={0}>{1}</color>",
                        Colors.Instance.GradeColors[g].ColorToHexString(),
                        string.Join(",", list)
                    ):holder;
                    count+=list.Count;
                }
                rowLabels[(int)Model.CharacterInfo.物品].text = string.Join(",", from str in strlst where !str.Contains(holder) select str)+(strlst[8]==holder?$"...等{count}个物品":string.Empty);
                // rowLabels[(int)Model.CharacterInfo.物品].renderMode =  TMPro.TextRenderFlags.DontRender;

                rowLabels[(int)Model.CharacterInfo.人物特性].text = string.Join(",", characterData.featureList);
            } else {
                for (int col = (int)Model.CharacterInfo.姓名; col <(int)Model.CharacterInfo._END_; ++col)
                {
                    rowLabels[col].text = "";
                }
            }
        }

        public void NextPage()
        {
            SearchResult(1);
        }

        public void PreviousPage()
        {
            SearchResult(-1);
        }

        #region filter
        private List<int> intInputValue = new List<int>();
        private List<string> stringInputValue = new List<string>();
        private List<bool> boolInputValue = new List<bool>();
        static bool _set_option=false;
        public void SetOptions() {
            _set_option=true;
        }
        public void _SetOptions() {
            // sortClick_curridx=-1; // refresh idx
            _set_option=false;
            GetIntInput();
            GetStringInput();
            GetBoolInput();
            // System.Diagnostics.Stopwatch w;
            // if(View.ToggleDic[Model.Toggle.并行查询].isOn){
            //     if(View.ToggleDic[Model.Toggle.顺序查询].isOn){
            //         w=System.Diagnostics.Stopwatch.StartNew();
            //         Model.Instance.CurrentDataList = Model.Instance.AllDataList.AsParallel().AsOrdered().Where(CheckSearchOption).ToList();
            //         w.Stop();
            //     } else {
            //         w=System.Diagnostics.Stopwatch.StartNew();
            //         Model.Instance.CurrentDataList = Model.Instance.AllDataList.AsParallel().Where(CheckSearchOption).ToList();
            //         w.Stop();
            //     }
            // } else {
                // w=System.Diagnostics.Stopwatch.StartNew();
            Model.Instance.CurrentDataList = Model.Instance.AllDataList.FindAll(character => CheckSearchOption(character));
                // w.Stop();
            // }
            // UnityEngine.Debug.LogError($"<color=#FFFF00>cost {w.ElapsedMilliseconds} ms</color>");

                // w=System.Diagnostics.Stopwatch.StartNew();
            RestoreSort();SearchResult(0);
                // w.Stop();
                // UnityEngine.Debug.LogError($"<color=#FFFF00>cost {w.ElapsedMilliseconds} ms</color>");
        }

        public bool CheckSearchOption(CharacterData character)
        {
            if (CheckInt(character) && CheckString(character) && CheckBool(character))
                return true;
            else
                return false;
        }

        public bool CheckInt(CharacterData character)
        {
            int minAge = intInputValue[(int)Model.Input.最低年龄];
            if (minAge != 0)
            {
                if (character.age < minAge)
                    return false;
            }
            int maxAge = intInputValue[(int)Model.Input.最大年龄];
            if (maxAge != 0)
            {
                if (character.age > maxAge)
                    return false;
            }

            int minInfection = intInputValue[(int)Model.Input.入魔值下限];
            if (minInfection != 0)
            {
                if (character.xiangshuInfection < minInfection)
                    return false;
            }
            int maxInfection = intInputValue[(int)Model.Input.入魔值上限];
            if (maxInfection != 0)
            {
                if (character.xiangshuInfection > maxInfection)
                    return false;
            }

            for (int index = (int)Model.Input.膂力, attributeIndex = 0; index <= (int)Model.Input.悟性; ++index, ++attributeIndex)
            {
                int value = intInputValue[index];
                if (value != 0)
                {
                    if (character.maxMainAttributes[attributeIndex] < value)
                        return false;
                }
            }
            int charm = intInputValue[(int)Model.Input.魅力];
            if (charm != 0)
            {
                if (character.attraction < charm)
                    return false;
            }
            int health = intInputValue[(int)Model.Input.健康];
            if (health != 0)
            {
                if (character.maxLeftHealth < health)
                    return false;
            }
            int samsara = intInputValue[(int)Model.Input.轮回次数];
            if (samsara != 0)
            {
                if (character.samsara.Length < samsara)
                    return false;
            }
            for (int index = (int)Model.Input.内功, combatSkillIndex = 0; index <= (int)Model.Input.乐器; ++index, ++combatSkillIndex)
            {
                int value = intInputValue[index];
                if (value != 0)
                {
                    if (character.combatSkillQualifications[combatSkillIndex] < value)
                        return false;
                }
            }
            for (int index = (int)Model.Input.音律, lifeSkillIndex = 0; index <= (int)Model.Input.杂学; ++index, ++lifeSkillIndex)
            {
                int value = intInputValue[index];
                if (value != 0)
                {
                    if (character.lifeSkillQualifications[lifeSkillIndex] < value)
                        return false;
                }
            }
            return true;
        }

        private Dictionary<string, List<string>> featureToGroup = null;
        private Dictionary<string, int> featureToLevel = null;

        private void SetupFeatureToGroup()
        {
            if (featureToGroup == null)
            {
                featureToGroup = new Dictionary<string, List<string>>();
                featureToLevel = new Dictionary<string, int>();

                List<string> tmp = null;
                var preMutexGroupId = -1;
                foreach (var feature in CharacterFeature.Instance)
                {
                    if (feature.TemplateId == 168)
                        return;
                    if (feature.MutexGroupId != preMutexGroupId)
                    {
                        preMutexGroupId = feature.MutexGroupId;
                        tmp = new List<string>();

                    }
                    tmp.Add(feature.Name);
                    featureToGroup[feature.Name] = tmp;
                    featureToLevel[feature.Name] = feature.Level;
                }
            }
        }
        public bool CheckString(CharacterData character)
        {
            string input = stringInputValue[0]; // 角色ID
            if (!input.IsNullOrEmpty())
            {
                if (!character.id.ToString().Equals(input))
                    return false;
            }

            input = stringInputValue[1]; // 姓名
            if (!input.IsNullOrEmpty())
            {
                if (!NMdict[character.name].Contains(input) && !character.preexistenceCharacterNames.Any(name => name?.Contains(input) ?? false))
                    return false;
            }

            input = stringInputValue[2]; // 归属
            if (!input.IsNullOrEmpty())
            {
                if ((!((byte)character.organizationInfo[0]).ToString("X2").Equals(input.ToUpper())) && (!character.organization.Contains(input)))
                    return false;
            }

            input = stringInputValue[3]; // 心仪
            if (!input.IsNullOrEmpty())
            {
                if (!((byte)character.ideal).ToString("X2").Equals(input.ToUpper())){
                    // var xxx=character.ideal.ToString("X2");
                    // MainEntry.logger($"{xxx} != {input.ToLower()}");
                    return false;
                }
            }

            input = stringInputValue[4];
            if (!input.IsNullOrEmpty())
            {
                if (int.TryParse(input.Substring(0, 1), out int identity))
                {
                    if (input.Length == 1 || input.Length == 2)
                    {
                        if (1 <= identity && identity <= 9)
                        {
                            int identityZerobase = 9 - identity;
                            if (input.Length == 1)
                            {
                                if (identityZerobase != character.organizationInfo[1])
                                {
                                    return false;
                                }
                            }
                            else if (input[1] == '+' && !(character.organizationInfo[1] >= identityZerobase))
                            {
                                return false;
                            }
                            else if (input[1] == '-' && !(character.organizationInfo[1] <= identityZerobase))
                            {
                                return false;
                            }
                        }
                    }
                }
                else if (!character.identify.Contains(input))
                {
                    return false;
                }
            }

            if (featureToGroup == null)
            {
                SetupFeatureToGroup();
            }

            Func<string, bool> wordNotMatchCharacterFeatureList = word =>
            {
                if(word.Length!=0 && word[0]!='-'){
                    if (word.Length == 4)
                    {
                        if (featureToGroup.ContainsKey(word))
                        {
                            return featureToGroup[word].All(targetFeature => list_not_contains_item(character.featureList, targetFeature));
                        }
                    }
                    else if (word.Length == 5)
                    {
                        var targetWord = word.Substring(0, 4);
                        if (featureToGroup.ContainsKey(targetWord))
                        {
                            return word[4] == '+' && featureToGroup[targetWord].All(targetFeature =>
                            featureToLevel[targetFeature] < 0 || list_not_contains_item(character.featureList, targetFeature));
                        }
                    }
                }

                return list_not_contains_item(character.featureList, word);
            };

            input = stringInputValue[5];
            if (!input.IsNullOrEmpty())
            {
                if (input.Contains("&") && input.Contains("|")){}
                else if (input.Contains("&"))
                {
                    var list = input.Split('&');

                    if (list.Any(word => wordNotMatchCharacterFeatureList(word)))
                        return false;
                }
                else if (input.Contains("|"))
                {
                    var list = input.Split('|');
                    if (list.All(word => wordNotMatchCharacterFeatureList(word)))
                        return false;
                }
                else
                {
                    if (wordNotMatchCharacterFeatureList(input))
                        return false;
                }
            }

            input = stringInputValue[6];
            if (!input.IsNullOrEmpty())
            {
                if (input.Contains("&") && input.Contains("|")){}
                else if (input.Contains("&"))
                {
                    var list = input.Split('&');
                    if (list.Any(item => list_not_contains_item(character.itemList, item)))
                        return false;
                }
                else if (input.Contains("|"))
                {
                    var list = input.Split('|');
                    if (list.All(item => list_not_contains_item(character.itemList, item)))
                        return false;
                }
                else
                {
                    if (list_not_contains_item(character.itemList, input))
                        return false;
                }
            }
            return true;
        }
        bool list_not_contains_item(IEnumerable<string> value, string item){
            if(item.Length==0){
                return false;
            }
            if(item[0]=='-'){
                item=item.Substring(1);
                return value.Any(x=>x.Contains(item));
            } else {
                return !value.Any(x=>x.Contains(item));
            }
        }
        public bool CheckBool(CharacterData character)
        {
            // if (character.isAlive == 0)
            //     return false;
            // if (!conditions_gender.Contains(character.gender))
            //     return false;
            // if (!conditions_behaviorType.Contains(character.behaviorType))
            //     return false;
            // if (!conditions_marriage.Contains(character.marriage))
            //     return false;
            //
            // return true;
            #pragma warning disable CS0219
            const int 无门无派=0;
            const int 门派=1;
            const int 太吾村=16;
            const int 外道=17;
            const int 城镇=21;
            const int 村庄=36;
            #pragma warning restore CS0219
            // if((conditions_life&(1<<character.isAlive))==0){MainEntry.logger($"{character.id} life mismatch 1<<{character.isAlive} vs {conditions_life}");}
            // if((conditions_gender&(1<<character.gender))==0){MainEntry.logger($"{character.id} gender mismatch 1<<{character.gender} vs {conditions_gender}");}
            // if((conditions_behaviorType&(1<<character.behaviorType))==0){MainEntry.logger($"{character.id} behaviorType mismatch 1<<{character.behaviorType} vs {conditions_behaviorType}");}
            // if((conditions_marriage&(1<<character.marriage))==0){MainEntry.logger($"{character.id} marriage mismatch 1<<{character.marriage} vs {conditions_marriage}");}
            // if((conditions_transgender&(character.transgender?1:0))==0){MainEntry.logger($"{character.id} transgender mismatch 1<<{character.transgender} vs {conditions_transgender}");}
            // if((conditions_bisexual&(character.bisexual?1:0))==0){MainEntry.logger($"{character.id} bisexual mismatch 1<<{character.bisexual} vs {conditions_bisexual}");}
            // if(((conditions_belong&(character.organizationInfo[0]<外道?(character.organizationInfo[0]<门派?1:(character.organizationInfo[0]<太吾村?2:4)):(character.organizationInfo[0]<城镇?8:character.organizationInfo[0]<村庄?16:32))))==0){MainEntry.logger($"{character.id} belong mismatch {character.organizationInfo[0]} vs {conditions_gender}");}
            return (conditions_life&(1<<character.isAlive))>0
                && (conditions_gender&(1<<character.gender))>0
                && (conditions_behaviorType&(1<<character.behaviorType))>0
                && (conditions_marriage&(1<<character.marriage))>0
                && (conditions_transgender&(character.transgender?2:1))>0
                && (conditions_bisexual&(character.bisexual?2:1))>0
                && (conditions_location&(character.location[0]==Utils.map.CurrentAreaId?(character.location[1]==Utils.map.CurrentBlockId?3:1):-2147483648))>0
                && (conditions_belong&(character.organizationInfo[0]<外道?(character.organizationInfo[0]<门派?1:(character.organizationInfo[0]<太吾村?2:4)):(character.organizationInfo[0]<城镇?8:character.organizationInfo[0]<村庄?16:32)))>0
                && (conditions_freedom&(-2147483648|(character.faction==-1?0:(character.faction==character.id?2:1))|(character.leader==-1?0:(character.leader==character.id?8:4))|(character.kidnapper==-1?0:16)))>0;
        }

        public void GetIntInput()
        {
            intInputValue.Clear();
            for (int index=(int)Model.Input.最低年龄; index<=(int)Model.Input.杂学; ++index)
            {
                int value = 0;
                int.TryParse(view.InputDic[(Model.Input)index].text, out value);
                intInputValue.Add(value);
            }

        }

        public void GetStringInput()
        {
            stringInputValue.Clear();
            for (int index = (int)Model.Input.角色ID; index <= (int)Model.Input.物品; ++index)
            {
                stringInputValue.Add(view.InputDic[(Model.Input)index].text);
            }
        }

        public static uint conditions_gender=uint.MaxValue;
        public static uint conditions_behaviorType=uint.MaxValue;
        public static uint conditions_marriage=uint.MaxValue;
        public static uint conditions_transgender=uint.MaxValue;
        public static uint conditions_bisexual=uint.MaxValue;
        public static uint conditions_location=uint.MaxValue;
        public static uint conditions_belong=uint.MaxValue;
        public static uint conditions_life=uint.MaxValue;
        public static uint conditions_freedom=uint.MaxValue;
        public void GetBoolInput()
        {
            uint FastGetEnumVal(Model.Toggle start, Model.Toggle end){
                if(View.ToggleDic[start].isOn){return uint.MaxValue;}
                uint ret=0;
                for (uint index = ((uint)start)+1; index <= (uint)end; ++index){
                    if(View.ToggleDic[(Model.Toggle)index].isOn){
                        ret|=1u<<(int)(index-1-(int)start);
                    }
                }
                return ret;
            }
            conditions_gender=FastGetEnumVal(Model.Toggle.全部性别, Model.Toggle.女性);
            conditions_gender=(uint)(conditions_gender&(~3)|((conditions_gender&1)<<1)|((conditions_gender&2)>>1));
            conditions_behaviorType=FastGetEnumVal(Model.Toggle.全部立场, Model.Toggle.唯我);
            conditions_marriage=FastGetEnumVal(Model.Toggle.全部婚姻, Model.Toggle.丧偶);
            conditions_transgender=FastGetEnumVal(Model.Toggle.全部生相, Model.Toggle.不同);
            conditions_bisexual=FastGetEnumVal(Model.Toggle.全部取向, Model.Toggle.双性);
            conditions_location=FastGetEnumVal(Model.Toggle.全世界, Model.Toggle.同地格);
            conditions_belong=FastGetEnumVal(Model.Toggle.全部归属, Model.Toggle.村庄);
            conditions_life=FastGetEnumVal(Model.Toggle.不论死活, Model.Toggle.健在);
            conditions_freedom=FastGetEnumVal(Model.Toggle.无关紧要, Model.Toggle.被拘禁);
            // MainEntry.logger($"conditions_gender:{conditions_gender}");
            // MainEntry.logger($"conditions_behaviorType:{conditions_behaviorType}");
            // MainEntry.logger($"conditions_marriage:{conditions_marriage}");
            // MainEntry.logger($"conditions_transgender:{conditions_transgender}");
            // MainEntry.logger($"conditions_bisexual:{conditions_bisexual}");
            // MainEntry.logger($"conditions_belong:{conditions_belong}");
        }
        #endregion

        public void ShowUI()
        {
            view.Show();
        }

        public void HideUI()
        {
            view.Hide();
        }

        public void OnDestroy()
        {
            view.Destroy();
        }
    }
}
#endif
